unit Main;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  ComCtrls, WinSkinData, CPort, _GClass, AbSwitch, AbDBCtrls, StdCtrls,
  AbDial, AbRMeter, AbLED, AbBevel, AbPanel, AbNumEdit, ExtCtrls, Db,
  ADODB, Grids, DBGrids, frxExportXLS, frxClass, frxExportPDF, frxCross;

const
  InputBoxMessage = WM_USER + 200;

type
  TMotorCtrl = class(TForm)
    PageCtrl: TPageControl;
    RunPage: TTabSheet;
    SettingPage: TTabSheet;
    Comm: TComPort;
    CommData: TComDataPacket;
    Skin: TSkinData;
    AbPanel1: TAbPanel;
    PowerSw: TAbDBRockerSwitch;
    MotorStatus1: TAbDBLED;
    MotorStatus2: TAbDBLED;
    Label1: TLabel;
    Label2: TLabel;
    Label3: TLabel;
    RunTimeEd: TEdit;
    NewModelBt: TButton;
    ActiveBt: TButton;
    TargetEd: TEdit;
    TimeOut: TTimer;
    SetSpeedBt: TButton;
    DBGrid: TDBGrid;
    ADOConn: TADOConnection;
    ModelADO: TADOTable;
    DataSource: TDataSource;
    DeleteModelBt: TButton;
    SampleTimer: TTimer;
    DB_TotalWheelEd: TEdit;
    Label4: TLabel;
    DB_ResetBt: TButton;
    DB_CurFreqEd: TEdit;
    Label7: TLabel;
    LostTimeEd: TEdit;
    Label8: TLabel;
    ModelCb: TComboBox;
    GetItemBt: TButton;
    ResetEditBt: TButton;
    Label11: TLabel;
    OTStatus: TAbDBLED;
    Label12: TLabel;
    PassADO: TADOTable;
    EnterAdjustEd: TButton;
    RunTimer: TTimer;
    LostTimer: TTimer;
    SaveBt: TButton;
    FrxReport: TfrxReport;
    frxPDFExport: TfrxPDFExport;
    frxXLSExport: TfrxXLSExport;
    frxCrossObject1: TfrxCrossObject;
    ReportBt: TButton;
    FreqVal: TAbDBDial;
    DoneBt: TButton;
    CtrlTimeout: TTimer;
    PollingStatusBt: TButton;
    PollingTimer: TTimer;
    GroupBox1: TGroupBox;
    Label9: TLabel;
    Label10: TLabel;
    DevAddr1: TComboBox;
    DevAddr2: TComboBox;
    SettingComPortBt: TButton;
    procedure InputBoxSetPasswordChar(var Msg: TMessage); message InputBoxMessage;
    function  GetPassword: String;
    procedure SetMotorSpeed(iMPerRound: real);
    procedure PowerSwClick(Sender: TObject);
    procedure FreqValValueChanged(Sender: TObject);
    procedure CommDataPacket(Sender: TObject; const Str: String);
    procedure TimeOutTimer(Sender: TObject);
    procedure SettingComPortBtClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure SetSpeedBtClick(Sender: TObject);
    procedure DeleteModelBtClick(Sender: TObject);
    procedure NewModelBtClick(Sender: TObject);
    procedure ActiveBtClick(Sender: TObject);
    procedure FormMouseWheel(Sender: TObject; Shift: TShiftState;
      WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean);
    procedure SampleTimerTimer(Sender: TObject);
    procedure DB_ResetBtClick(Sender: TObject);
    procedure GetItemBtClick(Sender: TObject);
    procedure ModelCbChange(Sender: TObject);
    procedure ResetEditBtClick(Sender: TObject);
    procedure EnterAdjustEdClick(Sender: TObject);
    procedure PageCtrlChange(Sender: TObject);
    procedure RunTimerTimer(Sender: TObject);
    procedure LostTimerTimer(Sender: TObject);
    procedure SaveBtClick(Sender: TObject);
    procedure FrxReportBeforePrint(Sender: TfrxReportComponent);
    procedure ReportBtClick(Sender: TObject);
    procedure DoneBtClick(Sender: TObject);
    procedure CtrlTimeoutTimer(Sender: TObject);
    procedure PollingStatusBtClick(Sender: TObject);
    procedure PollingTimerTimer(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  MotorCtrl: TMotorCtrl;

const
  TIME_WORK = 440;
  TIME_OT = 170;

  STEP_PER_ROUND = 20000;

  COMPORT       = 'COM1';
  DIFF_SPEED    = 3;
  FREQ_STEP     = 5;

  SW_ADDR               = $80;
  GET_STATUS_CMD        = $73;
  SW_ON_ACTIVE          = $80;
  SW_OFF_ACTIVE         = $40;

  MOTOR_READ_4COIL_CMD  = $01;
  MOTOR_WRITE_1COIL_CMD = $05;

  MOTOR_READ_8REG_CMD   = $03;
  MOTOR_WRITE_1REG_CMD  = $06;
  MOTOR_WRITE_8REG_CMD  = $10;

  TURN_ON_MOTOR1_CMD    = $80;
  TURN_ON_MOTOR2_CMD    = $81;
  TURN_OFF_MOTOR1_CMD   = $82;
  TURN_OFF_MOTOR2_CMD   = $83;

  SET_SPEED_MOTOR1_CMD  = $84;
  SET_SPEED_MOTOR2_CMD  = $85;

var
  m_WaitRecFlag : bool;
  m_pRxBuff: array [0..160] of byte;
  m_RxCount: integer;
  m_Mode: byte;

  m_WheelTotal: Integer;

  m_CurFreq: Integer;
  m_SetSpeed: Integer;

  m_RunningFlag : bool;

  m_PassOK: bool;
  m_OldModel: String;

  m_IsDateReport : Boolean;

implementation

{$R *.DFM}

function GetChecksum(pBuff: array of byte; iLen: integer): WORD;
var
  temp: WORD;
  crc: WORD;
  i,j: integer;
begin
  crc := $FFFF;
  for i := 0 to iLen - 1 do
  begin
    crc := ( (crc xor pBuff[i]) or $FF00 ) and (crc or $00FF);
    for j := 0 to 7 do
    begin
      temp := crc and $0001;
      crc := crc shr 1;
      if temp > 0 then
      begin
        crc := crc xor $A001;
      end;
    end;
  end;
  GetChecksum := crc;
end;

Function strtohex(s:string):Byte;
var k1,k2:byte;
begin
k1:=0;
k2:=0;
case S[1] of
'0' : k1:=$00;
'1' : K1:=$10;
'2' : k1:=$20;
'3' : K1:=$30;
'4' : k1:=$40;
'5' : K1:=$50;
'6' : k1:=$60;
'7' : K1:=$70;
'8' : k1:=$80;
'9' : K1:=$90;
'A' : k1:=$A0;
'B' : K1:=$B0;
'C' : k1:=$C0;
'D' : K1:=$D0;
'E' : k1:=$E0;
'F' : K1:=$F0;
end;
case S[2] of
'0' : k2:=$00;
'1' : K2:=$01;
'2' : k2:=$02;
'3' : K2:=$03;
'4' : k2:=$04;
'5' : K2:=$05;
'6' : k2:=$06;
'7' : K2:=$07;
'8' : k2:=$08;
'9' : K2:=$09;
'A' : k2:=$0A;
'B' : K2:=$0B;
'C' : k2:=$0C;
'D' : K2:=$0D;
'E' : k2:=$0E;
'F' : K2:=$0F;
end;
strtohex := k1 or k2;
end;

Function hextostr(i:byte):String;
var k1,k2 : byte;
    sstr,str2 : string;
begin
k1:= i and $F0;
k2:= i and $0F;
case k1 of
$00: sstr:='0';
$10: sstr:='1';
$20: sstr:='2';
$30: sstr:='3';
$40: sstr:='4';
$50: sstr:='5';
$60: sstr:='6';
$70: sstr:='7';
$80: sstr:='8';
$90: sstr:='9';
$A0: sstr:='A';
$B0: sstr:='B';
$C0: sstr:='C';
$D0: sstr:='D';
$E0: sstr:='E';
$F0: sstr:='F';
end;
case k2 of
$00: str2:='0';
$01: str2:='1';
$02: str2:='2';
$03: str2:='3';
$04: str2:='4';
$05: str2:='5';
$06: str2:='6';
$07: str2:='7';
$08: str2:='8';
$09: str2:='9';
$0A: str2:='A';
$0B: str2:='B';
$0C: str2:='C';
$0D: str2:='D';
$0E: str2:='E';
$0F: str2:='F';
end;
hextostr := sstr + str2;
end;

  //chuong trinh lay ve duong dan chuong trinh hoat dong
function GetAppPath:string;
var x,y:string;
begin
  x := ParamStr(0);
  y := ExtractFileName(ParamStr(0));
  Result := copy(x,0,length(x) - length(y));
end;


function IncTime(ATime: TDateTime; Hours, Minutes, Seconds,
  MSecs: Integer): TDateTime;
begin
  Result := ATime + (Hours div 24) + (((Hours mod 24) * 3600000 +
    Minutes * 60000 + Seconds * 1000 + MSecs) / MSecsPerDay);
  if Result < 0 then
    Result := Result + 1;
end;

function IncSecond(iTime: String): String;
var
  hour, minute, second: integer;
  time: TDateTime;
begin
  hour := StrToInt(copy(iTime, 1, 2));
  minute := StrToInt(copy(iTime, 4, 2));
  second := StrToInt(copy(iTime, 7, 2));
  inc(second);
  if second >= 60 then
  begin
    second := 0;
    inc(minute);
    if (minute >= 60) then
    begin
      minute := 0;
      inc(hour);
    end;
  end;
  time := EncodeTime(hour, minute, second, 0);
  Result := formatDateTime('hh:mm:ss', time);
end;


procedure TMotorCtrl.InputBoxSetPasswordChar(var Msg: TMessage);
var
  hInputForm, hEdit: HWND;
begin
  hInputForm := Screen.Forms[0].Handle;
  if (hInputForm <> 0) then
  begin
    hEdit := FindWindowEx(hInputForm, 0, 'TEdit', nil);
    SendMessage(hEdit, EM_SETPASSWORDCHAR, Ord('*'), 0);
  end;
end;

function TMotorCtrl.GetPassword: String;
begin
  PostMessage(Handle, InputBoxMessage, 0, 0);
  Result := InputBox('Enter password', 'Password:', '');
end;

procedure TMotorCtrl.SetMotorSpeed(iMPerRound: real);
begin
  m_SetSpeed := Round( STEP_PER_ROUND / ( iMPerRound * 60 ) );
  FreqVal.SignalSettings.Name2 := IntToStr(m_SetSpeed);
end;

procedure TMotorCtrl.PowerSwClick(Sender: TObject);
var
  pBuff: array [0..16] of byte;
  crc : WORD;
begin
  if PowerSw.Checked = true then
  begin
    if Comm.Connected = true then
    begin
      PollingTimer.Enabled := false;
      pBuff[0] := DevAddr1.ItemIndex + 1;
      pBuff[1] := MOTOR_WRITE_1COIL_CMD;
      pBuff[2] := $00;
      pBuff[3] := $00;
      pBuff[4] := $FF;
      pBuff[5] := $00;
      crc := GetChecksum(pBuff, 6);
      pBuff[6] := crc mod $100;
      pBuff[7] := crc div $100;

      comm.Write(pBuff, 8);
      m_WaitRecFlag := true;
      m_RxCount := 0;
      m_Mode := TURN_ON_MOTOR1_CMD;
      CtrlTimeout.Enabled := True;
      PollingTimer.Enabled := true;

      RunTimer.Enabled := true;
      LostTimer.Enabled := false;
      SaveBtClick(self);
      PollingTimer.Enabled := true;
    end
    else
    begin
      ShowMessage('Connect comport first!');
    end;
  end
  else
  begin
    if Comm.Connected = true then
    begin
      PollingTimer.Enabled := false;
      pBuff[0] := DevAddr1.ItemIndex + 1;
      pBuff[1] := MOTOR_WRITE_1COIL_CMD;
      pBuff[2] := $00;
      pBuff[3] := $00;
      pBuff[4] := $00;
      pBuff[5] := $00;
      crc := GetChecksum(pBuff, 6);
      pBuff[6] := crc mod $100;
      pBuff[7] := crc div $100;

      comm.Write(pBuff, 8);
      m_WaitRecFlag := true;
      m_RxCount := 0;
      m_Mode := TURN_OFF_MOTOR1_CMD;
      CtrlTimeout.Enabled := True;
      PollingTimer.Enabled := true;

      RunTimer.Enabled := false;
      LostTimer.Enabled := true;
      SaveBtClick(self);

      m_CurFreq := 100;
      DB_CurFreqEd.Text := IntToStr(m_CurFreq);
    end
    else
    begin
      ShowMessage('Connect COM port first');
    end;
  end;
end;

procedure TMotorCtrl.FreqValValueChanged(Sender: TObject);
begin
  SetMotorSpeed( FreqVal.Value );

  m_PassOK := false;
  FreqVal.Enabled := false;
end;

procedure TMotorCtrl.CommDataPacket(Sender: TObject; const Str: String);
var
  i: integer;
begin
  if m_WaitRecFlag = true then
  begin
    Timeout.Enabled := false;

    for I := 1 to Length(str) do
    begin
      m_pRxBuff[m_RxCount] := ord(str[i]);
      inc(m_RxCount);
    end;

    Timeout.Enabled := true;
  end;
end;

procedure TMotorCtrl.TimeOutTimer(Sender: TObject);
var
  crc : WORD;
  pBuff: array [0..16] of byte;
  temp : WORD;
begin
  Timeout.Enabled := false;
  m_WaitRecFlag := false;

  case m_Mode of
  SET_SPEED_MOTOR1_CMD:
    begin
      if (m_pRxBuff[0] = DevAddr1.ItemIndex+1) and (m_pRxBuff[1] = MOTOR_WRITE_1REG_CMD) then
      begin
        MotorStatus1.Checked := true;

        PollingTimer.Enabled := false;
        pBuff[0] := DevAddr2.ItemIndex + 1;
        pBuff[1] := MOTOR_WRITE_1REG_CMD;
        pBuff[2] := $00;
        pBuff[3] := $01;
        temp := m_CurFreq mod $10000;
        pBuff[4] := temp div $100;
        pBuff[5] := temp mod $100;
        crc := GetChecksum(pBuff, 6);
        pBuff[6] := crc mod $100;
        pBuff[7] := crc div $100;

        comm.Write(pBuff, 8);
        m_WaitRecFlag := true;
        m_RxCount := 0;
        m_Mode := SET_SPEED_MOTOR2_CMD;
        PollingTimer.Enabled := true;
      end;
    end;

  SET_SPEED_MOTOR2_CMD:
    begin
      if (m_pRxBuff[0] = DevAddr1.ItemIndex+1) and (m_pRxBuff[1] = MOTOR_WRITE_1REG_CMD) then
      begin
        MotorStatus2.Checked := true;
        CtrlTimeout.Enabled := False;
      end;
    end;

  TURN_ON_MOTOR1_CMD:
    begin
      if (m_pRxBuff[0] = DevAddr1.ItemIndex+1) and (m_pRxBuff[1] = MOTOR_WRITE_1COIL_CMD) then
      begin
        MotorStatus1.Checked := true;
        
        PollingTimer.Enabled := false;
        pBuff[0] := DevAddr2.ItemIndex + 1;
        pBuff[1] := MOTOR_WRITE_1COIL_CMD;
        pBuff[2] := $00;
        pBuff[3] := $00;
        pBuff[4] := $FF;
        pBuff[5] := $00;
        crc := GetChecksum(pBuff, 6);
        pBuff[6] := crc mod $100;
        pBuff[7] := crc div $100;

        comm.Write(pBuff, 8);
        m_WaitRecFlag := true;
        m_RxCount := 0;
        m_Mode := TURN_ON_MOTOR2_CMD;
        PollingTimer.Enabled := true;
      end;
    end;

  TURN_ON_MOTOR2_CMD:
    begin
      if (m_pRxBuff[0] = DevAddr2.ItemIndex+1) and (m_pRxBuff[1] = MOTOR_WRITE_1COIL_CMD) then
      begin
        MotorStatus2.Checked := true;
        m_RunningFlag := true;
        CtrlTimeout.Enabled := False;
      end;
    end;

  TURN_OFF_MOTOR1_CMD:
    begin
      if (m_pRxBuff[0] = DevAddr1.ItemIndex+1) and (m_pRxBuff[1] = MOTOR_WRITE_1COIL_CMD) then
      begin
        MotorStatus1.Checked := false;

        PollingTimer.Enabled := false;
        pBuff[0] := DevAddr2.ItemIndex + 1;
        pBuff[1] := MOTOR_WRITE_1COIL_CMD;
        pBuff[2] := $00;
        pBuff[3] := $00;
        pBuff[4] := $00;
        pBuff[5] := $00;
        crc := GetChecksum(pBuff, 6);
        pBuff[6] := crc mod $100;
        pBuff[7] := crc div $100;

        comm.Write(pBuff, 8);
        m_WaitRecFlag := true;
        m_RxCount := 0;
        m_Mode := TURN_OFF_MOTOR2_CMD;
        PollingTimer.Enabled := true;
      end;
    end;

  TURN_OFF_MOTOR2_CMD:
    begin
      if (m_pRxBuff[0] = DevAddr2.ItemIndex+1) and (m_pRxBuff[1] = MOTOR_WRITE_1COIL_CMD) then
      begin
        MotorStatus2.Checked := false;
        m_RunningFlag := false;
        CtrlTimeout.Enabled := False;
      end;
    end;

  GET_STATUS_CMD:
    begin
      if (m_pRxBuff[0] = SW_ADDR) and (m_pRxBuff[1] = GET_STATUS_CMD) then
      begin
        if ( m_pRxBuff[2] and SW_ON_ACTIVE ) > 0 then
        begin
          PowerSw.Checked := True;
          PowerSwClick(self);
        end
        else if ( m_pRxBuff[2] and SW_OFF_ACTIVE ) > 0 then
        begin
          PowerSw.Checked := False;
          PowerSwClick(self);
        end;
        //Status.Text := (HexToStr(pRxBuff[2]));
      end;
    end

  else
  begin
    {
    Status.Lines.Add(IntToHex(RxCount, 4));

    s := '';
    for I := 0 to RxCount - 1 do
    begin
      s := s + IntToHex(pRxBuff[i], 2) +' ';
    end;
    Status.Lines.Add(s);
    }
  end;
  end;
  m_RxCount := 0;
end;

procedure TMotorCtrl.SettingComPortBtClick(Sender: TObject);
begin
  Comm.ShowSetupDialog;
end;

procedure TMotorCtrl.FormCreate(Sender: TObject);
var
  dbname, pwd : string;
begin
  DBGrid.Height := SettingPage.Height - 100;
  DevAddr1.ItemIndex := 0;
  DevAddr2.ItemIndex := 1;

  m_RunningFlag := false;
  m_WaitRecFlag := false;
  m_WheelTotal := 0;
  m_PassOK := false;
  m_OldModel := '';
  m_IsDateReport := True;
  dbname:=GetAppPath()+'MotorCtrldb.mdb';

  if ADOConn.Connected = true then exit;
  pwd := '';
  ADOConn.ConnectionString:='Provider=Microsoft.Jet.OLEDB.4.0;Data Source=' + dbname + ';Persist Security Info=False';
  if pwd <> '' then ADOConn.ConnectionString:=ADOConn.ConnectionString + ';Jet OLEDB:Database Password=' + pwd;

  ADOConn.LoginPrompt := False;

  try
    if NOT ADOConn.Connected then ADOConn.Open;
  except
    ON E:Exception do
    begin
      MessageDlg(e.Message,mtError, [mbOK],0);
      pwd := InputBox('MDB with password','If this is password protected, please enter password (leave empty to cancel):','');
      if pwd = '' then
      begin
        Exit;
      end;
    end;
  end;

  PassADO.TableName := 'Pass';
  PassADO.Active := true;
  if (PassADO.RecordCount = 0) then PassADO.InsertRecord( [123456, 6789] );

  ModelADO.TableName := 'Model';
  ModelADO.Active := true;
  if (ModelADO.RecordCount = 0) then NewModelBtClick(self);

  DBGrid.Columns.Items[0].Width := 320;
  DBGrid.Columns.Items[1].Width := 85;
  DBGrid.Columns.Items[2].Width := 60;
  DBGrid.Columns.Items[3].Width := 115;
  DBGrid.Columns.Items[4].Width := 115;
  DBGrid.Columns.Items[5].Width := 120;

  ResetEditBtClick(self);

  GetItemBtClick(self);
  ActiveBtClick(self);
end;

procedure TMotorCtrl.SetSpeedBtClick(Sender: TObject);
var
  pBuff: array [0..16] of byte;
  crc : WORD;
  temp : Integer;
begin
  if Comm.Connected = true then
  begin
    MotorStatus1.Checked := false;
    MotorStatus2.Checked := false;
  
    PollingTimer.Enabled := false;
    pBuff[0] := DevAddr1.ItemIndex + 1;
    pBuff[1] := MOTOR_WRITE_1REG_CMD;
    pBuff[2] := $00;
    pBuff[3] := $01;
    temp := m_CurFreq mod $10000;
    pBuff[4] := temp div $100;
    pBuff[5] := temp mod $100;
    crc := GetChecksum(pBuff, 6);
    pBuff[6] := crc mod $100;
    pBuff[7] := crc div $100;

    comm.Write(pBuff, 8);
    m_WaitRecFlag := true;
    m_RxCount := 0;
    m_Mode := SET_SPEED_MOTOR1_CMD;
    CtrlTimeout.Enabled := True;
    PollingTimer.Enabled := true;
  end;
end;

procedure TMotorCtrl.DeleteModelBtClick(Sender: TObject);
begin
  if (ModelADO.RecordCount = 0) then exit;
  ModelADO.Delete;
  if ModelADO.Locate('Model', ModelCb.Text, []) = false then
  begin
    ResetEditBtClick(self);
  end;

  if (ModelADO.RecordCount = 0) then NewModelBtClick(self);
  GetItemBtClick(self);
end;

procedure TMotorCtrl.NewModelBtClick(Sender: TObject);
var
  i: integer;
  s: string;
  myDateTime: TDateTime;
  dateStr: string;
  timeStr: string;
begin
  i := 0;
  repeat
    inc(i);
    s := 'Model' + IntToStr(i);
  until (ModelADO.Locate('Model', s, []) = false);
  myDateTime := now;
  dateStr := FormatDateTime('DD/MM/YYYY', myDateTime);
  myDateTime := EncodeTime(00, 00, 00, 000);
  timeStr := FormatDateTime('hh:mm:ss', myDateTime);
  ModelADO.InsertRecord([s, '0', 'No', timeStr, timeStr, dateStr]);
  
  GetItemBtClick(self);
end;

procedure TMotorCtrl.ActiveBtClick(Sender: TObject);
var
  target: integer;
  s: string;
begin
  if (ModelADO.RecordCount > 0) then
  begin
    if ModelADO.Locate('Model', ModelADO.FieldValues['Model'], [])=true then
    begin
      ModelCb.Text := ModelADO.FieldValues['Model'];
      m_OldModel := ModelCb.Text;
      TargetEd.Text := ModelADO.FieldValues['Target'];
      target := StrToInt(TargetEd.Text);
      s := ModelADO.FieldValues['OT'];
      if ( (s = 'Yes') or (s = 'yes') or (s = 'Y') or (s = 'y') ) then
      begin
        OTStatus.Checked := true;
        target := ( target * (TIME_WORK + TIME_OT) ) div 60;
        OTStatus.Caption := '  => Target on day: ' + IntToStr( target ) + ' products/day';
      end
      else
      begin
        OTStatus.Checked := false;
        target := ( target * TIME_WORK ) div 60;
        OTStatus.Caption := '  => Target on day: ' + IntToStr( target ) + ' products/day';
      end;
      RunTimeEd.Text := ModelADO.FieldValues['RunTime'];
      LostTimeEd.Text := ModelADO.FieldValues['LostTime'];
      
      target := StrToInt(TargetEd.Text);
      if target > 0 then
      begin
        FreqVal.Value := 60 / target;
        SetMotorSpeed(60 / target);
        m_CurFreq := 100;
      end
      else
      begin
        FreqVal.Value := 0;
        SetMotorSpeed(0);
        m_CurFreq := 0;
      end;
      DB_CurFreqEd.Text := IntToStr(m_CurFreq);
      
      PowerSw.Checked := false;
      m_OldModel := ModelCb.Text;
      PowerSwClick(self);
      RunTimer.Enabled := false;
      LostTimer.Enabled := false;
    end;
  end;
end;

procedure TMotorCtrl.FormMouseWheel(Sender: TObject; Shift: TShiftState;
  WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean);
begin
  if (WheelDelta > 0) then
  begin
    m_WheelTotal := m_WheelTotal + WheelDelta;
  end;
end;

procedure TMotorCtrl.SampleTimerTimer(Sender: TObject);
var
  curSpeed: Integer;
begin
  curSpeed := m_WheelTotal div 120;
  m_WheelTotal := 0;
  FreqVal.SignalSettings.Name1 := 'CurSpeed: ' + IntToStr( curSpeed );
  DB_TotalWheelEd.Text := IntToStr( StrToInt(DB_TotalWheelEd.Text) + curSpeed );

  if m_RunningFlag = True then
  begin
    if curSpeed > m_SetSpeed + DIFF_SPEED then
    begin
      m_CurFreq := m_CurFreq - FREQ_STEP;
      SetSpeedBtClick(self);
    end
    else if curSpeed < m_SetSpeed - DIFF_SPEED then
    begin
      m_CurFreq := m_CurFreq + FREQ_STEP;
      SetSpeedBtClick(self);
    end;
  end;

  DB_CurFreqEd.Text := IntToStr(m_CurFreq);
end;

procedure TMotorCtrl.DB_ResetBtClick(Sender: TObject);
begin
  DB_TotalWheelEd.Text := '0';
end;

procedure TMotorCtrl.GetItemBtClick(Sender: TObject);
var
  i: integer;
  index, s: string;
begin
  if (ModelADO.RecordCount > 0) then
  begin
    index := ModelADO.FieldValues['Model'];
    ModelCb.Items.Clear;
    ModelADO.First;

    for i:= 0 to ModelADO.RecordCount - 1 do
    begin
      s := ModelADO.FieldValues['Model'];
      ModelCb.Items.Add(s);
      if (i < ModelADO.RecordCount - 1) then ModelADO.Next;
    end;

    ModelADO.Locate('Model', index, []);
  end
  else
  begin

  end;
end;

procedure TMotorCtrl.ModelCbChange(Sender: TObject);
begin
  if ((m_OldModel <> '') and (m_OldModel <> ModelCb.Text)) then
  begin
    SaveBtClick(self);
  end;

  if ModelADO.Locate('Model', ModelCb.Text, []) = true then
  begin
    ActiveBtClick(self);
  end;
end;

procedure TMotorCtrl.ResetEditBtClick(Sender: TObject);
begin
  ModelCb.Clear;
  ModelCb.Items.Clear;
  TargetEd.Clear;
  RunTimeEd.Clear;
  LostTimeEd.Clear;
end;

procedure TMotorCtrl.EnterAdjustEdClick(Sender: TObject);
var
  pass: string;
  passStore: string;
begin
  if (m_PassOK = false) then
  begin
    pass := MotorCtrl.GetPassword;
    PassADO.First;
    passStore := PassADO.FieldValues['Adj'];
    if (pass = passStore) then
    begin
      m_PassOK := true;
      FreqVal.Enabled := true;
    end
    else
      showmessage('Password incorrect!');
  end;
end;

procedure TMotorCtrl.PageCtrlChange(Sender: TObject);
var
  pass: string;
  passStore: string;
begin
  if (PageCtrl.ActivePageIndex = 1) then
  begin
    PageCtrl.ActivePageIndex := 0;
    pass := MotorCtrl.GetPassword;
    PassADO.First;
    passStore := PassADO.FieldValues['Setting'];
    if (pass <> passStore) then
    begin
      showmessage('Password incorrect!');
    end
    else
    begin
      PageCtrl.ActivePageIndex := 1;
      DBGrid.Height := SettingPage.Height - 80;
    end;
  end;
end;

procedure TMotorCtrl.RunTimerTimer(Sender: TObject);
begin
  if (m_RunningFlag = true) and (length(RunTimeEd.Text) = 8) then
  begin
    RunTimeEd.Text := IncSecond(RunTimeEd.Text);
  end;
end;

procedure TMotorCtrl.LostTimerTimer(Sender: TObject);
begin
  if (m_RunningFlag = false) and (length(LostTimeEd.Text) = 8) then
  begin
    LostTimeEd.Text := IncSecond(LostTimeEd.Text);
  end;
end;

procedure TMotorCtrl.SaveBtClick(Sender: TObject);
begin
  if (ModelADO.Locate('Model', m_OldModel, []) = true) then
  begin
    ModelADO.Edit;
    ModelADO.FieldByName('RunTime').Value := RunTimeEd.Text;
    ModelADO.FieldByName('LostTime').Value := LostTimeEd.Text;
    ModelADO.FieldByName('DateTime').Value := FormatDateTime('DD/MM/YYYY', now);
    ModelADO.Post;
  end;
end;


procedure TMotorCtrl.FrxReportBeforePrint(Sender: TfrxReportComponent);
var
  Cross: TfrxCrossView;
  i: Integer;
begin
  if Sender is TfrxCrossView then
  begin
    Cross := TfrxCrossView(Sender);
    for i := 0 to ModelADO.RecordCount - 1 do
    begin
      //if () then
      begin

      end;
    end;

    Cross.AddValue([0], ['Model'], [10]);
    Cross.AddValue([0], ['Target'], [11]);
    Cross.AddValue([0], ['OverTime'], [12]);
    Cross.AddValue([0], ['RunTime'], ['13:45:53']);
    Cross.AddValue([0], ['LostTime'], [14]);
    Cross.AddValue([0], ['Date'], [15]);
  end;
end;

procedure TMotorCtrl.ReportBtClick(Sender: TObject);
var
  Cross: TfrxCrossView;
begin
  m_IsDateReport := True;
  //FrxReport.ShowReport;
  if Sender is TfrxCrossView then
  begin
    Cross := TfrxCrossView(Sender);
    Cross.AddValue([0], ['Model'], [10]);
    Cross.AddValue([0], ['Target'], [11]);
    Cross.AddValue([0], ['OverTime'], [12]);
    Cross.AddValue([0], ['RunTime'], ['13:45:53']);
    Cross.AddValue([0], ['LostTime'], [14]);
    Cross.AddValue([0], ['Date'], [15]);
  end;
  FrxReport.SaveToFile(GetAppPath() + 'report.pdf');
end;

procedure TMotorCtrl.DoneBtClick(Sender: TObject);
begin
  PowerSw.Checked := False;
  SaveBtClick(self);
  PowerSwClick(self);
  
  RunTimer.Enabled := False;
  LostTimer.Enabled:= False;
end;

procedure TMotorCtrl.CtrlTimeoutTimer(Sender: TObject);
begin
  MotorStatus1.Checked := False;
  MotorStatus2.Checked := False;
  CtrlTimeout.Enabled := False;
end;

procedure TMotorCtrl.PollingStatusBtClick(Sender: TObject);
var
  pBuff: array [0..16] of byte;
  crc : WORD;
begin
  if Comm.Connected = true then
  begin
    pBuff[0] := SW_ADDR;
    pBuff[1] := GET_STATUS_CMD;
    crc := GetChecksum(pBuff, 2);
    pBuff[2] := crc mod $100;
    pBuff[3] := crc div $100;

    comm.Write(pBuff, 4);
    m_WaitRecFlag := true;
    m_RxCount := 0;
    m_Mode := GET_STATUS_CMD;
  end;
end;

procedure TMotorCtrl.PollingTimerTimer(Sender: TObject);
begin
  PollingStatusBtClick(Self);
end;

end.
